﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Drawing;



namespace ParticleEditor
{
    public enum emitShape { Rectangle, Circle, Line, Point }
    class Emitter
    {
        List<Particle> m_lParticlez = new List<Particle>();
        //private float spawnTime;
        public Emitter()
        {
            m_nEmitterID = -1;
            m_sParticleName = string.Empty;
            eShape = 0;
            m_nShape = -1;
            m_fEmissionRate = 0;
            m_fSpawnTime = 0;
            m_fMaxLife = 0;
            m_fMinLife = 0;
            m_fPositionX = 300;
            m_fPositionY = 150;
            m_fRotationEnd = 0;
            m_fRotationStart = 0;
            m_fScaleEnd = 0;
            m_fScaleStart = 0;
            m_fVelocityEndX = 0;
            m_fVelocityEndY = 0;
            m_fVelocityStartX = 0;
            m_fVelocityStartY = 0; ;
            m_nMaxParticles = 0;
            m_bIsLooping = true;
            m_ptMouse = new Point((int)m_fPositionX, (int)m_fPositionY);
        }

        public void Explosion()
        {
            for (int i = 0; i < m_nMaxParticles; i++)
            {
                CreateParticle();
            }
        }

        public bool Update(float fElapsedTime)
        {
            Particle part;
            int count = m_lParticlez.Count;

            // For Loop or Burst
            if (m_bIsLooping)
            {
                if (count < m_nMaxParticles)
                {
                    if (m_fSpawnTime > m_fEmissionRate)
                    {
                        CreateParticle();
                        m_fSpawnTime = 0.0f;
                    }

                    m_fSpawnTime += fElapsedTime;
                }
            }
            else if( !m_bIsLooping )
            {
                if (count <= 0)
                {
                    Explosion();
                }
            }
            
            for (int i = 0; i < count; i++)
            {
                part = (Particle)m_lParticlez[i];

                // Time between its life and being dead
                float alpha = (float)part.m_fCurrLife / (float)part.m_fMaxLife;

                // Snap to true values of life
                if (alpha > 1.0f)
                    alpha = 1.0f;
                else if (alpha < 0)
                    alpha = 0;

                // Position based on velocity
                if (m_fVelocityEndX > m_fVelocityStartX)
                {
                    part.m_fCurrPostionX += part.m_fCurrVelocityX * (((m_fVelocityEndX - m_fVelocityStartX) * alpha) + m_fVelocityEndX);
                }
                else
                {
                    part.m_fCurrPostionX += part.m_fCurrVelocityX * (((m_fVelocityEndX - m_fVelocityStartX) * alpha) + m_fVelocityStartX);
                }

                if (m_fVelocityEndY > m_fVelocityStartY)
                {
                    part.m_fCurrPostionY += part.m_fCurrVelocityY * (((m_fVelocityEndY - m_fVelocityStartY) * alpha) + m_fVelocityEndY);
                }
                else
                {
                    part.m_fCurrPostionY += part.m_fCurrVelocityY * (((m_fVelocityEndY - m_fVelocityStartY) * alpha) + m_fVelocityStartY);
                }

                // Particle Rotation
                part.m_fCurrRotation = m_fRotationStart + ((m_fRotationEnd - m_fRotationStart) * alpha) * (float)(Math.PI / 180);

                // Particle Scale
                part.m_fCurrScale = m_fScaleStart + ((m_fScaleEnd - m_fScaleStart) * alpha);

                // Particle Color change
                part.m_cCurrColor = Color.FromArgb(
                    (int)(cStartColor.A + (cEndColor.A - cStartColor.A) * alpha),
                    (int)(cStartColor.R + (cEndColor.R - cStartColor.R) * alpha),
                    (int)(cStartColor.G + (cEndColor.G - cStartColor.G) * alpha),
                    (int)(cStartColor.B + (cEndColor.B - cStartColor.B) * alpha));

                // Checking if particle is dead
                if (part.m_fCurrLife > part.m_fMaxLife)
                {
                    m_lParticlez.RemoveAt(i);

                    i--;
                    count = m_lParticlez.Count;
                }
                
                part.m_fCurrLife += fElapsedTime;
            }
            return true;
        }

        Random r = new Random();
        public void Render()
        {
            Rectangle source = new Rectangle(0, 0, 64, 64);
            foreach (Particle p in m_lParticlez)
            {
                int rotx = source.Width / 2;
                int roty = source.Height / 2;

                ManagedTextureManager.Instance.Draw(m_nEmitterID, (int)p.m_fCurrPostionX, (int)p.m_fCurrPostionY,
                     p.m_fCurrScale, p.m_fCurrScale, source, rotx, roty,
                     p.m_fCurrRotation, p.m_cCurrColor);
            }
        }

        public void CreateParticle()
        {
            Particle p = new Particle();
            int tempMin = ((int)m_fMaxLife > (int)m_fMinLife ? (int)m_fMinLife : (int)m_fMaxLife);
            int tempMax = ((int)m_fMaxLife > (int)m_fMinLife ? (int)m_fMaxLife : (int)m_fMinLife);

            p.m_fMaxLife = tempMin + (r.Next(100) / 100.0f) * (tempMax - tempMin);
            if (p.m_fMaxLife <= 0)
                return;

            p.m_fCurrLife = 0;

            Size sz = new Size(64, 64);

            Rectangle rect = new Rectangle(m_ptMouse, sz);

            if (eShape == emitShape.Rectangle)
            {
                rect.X -= sz.Width / 2;
                rect.Y -= sz.Height / 2;

                p.m_fCurrPostionX = r.Next(rect.Left, rect.Right);
                p.m_fCurrPostionY = r.Next(rect.Top, rect.Bottom);
            }
            else if (eShape == emitShape.Line)
            {
                Point endPos = new Point(400, 150);

                p.m_fCurrPostionX = r.Next((int)m_fPositionX, endPos.X);
                p.m_fCurrPostionY = m_fPositionY;
            }
            else if (eShape == emitShape.Circle)
            {
                Point midCircle = new Point(rect.X -= sz.Width / 2, rect.Y -= sz.Height / 2);
                float radius = 32.0f;

                float randomNum = (float)r.NextDouble() * radius;

                float rotation = r.Next(628) / 100.0f;
                float vX = (float)Math.Cos(rotation);
                float vY = (float)Math.Sin(rotation);
                p.m_fCurrPostionX = midCircle.X + vX * randomNum;
                p.m_fCurrPostionY = midCircle.Y + vY * randomNum;
            }
            else if (eShape == emitShape.Point)
            {
                p.m_fCurrPostionX = m_ptMouse.X;
                p.m_fCurrPostionY = m_ptMouse.Y;
            }

            float tempMinVX = (m_fVelocityEndX > m_fVelocityStartX ? m_fVelocityStartX : m_fVelocityEndX);
            float tempMaxVX = (m_fVelocityEndX > m_fVelocityStartX ? m_fVelocityEndX : m_fVelocityStartX);
            float tempMinVY = (m_fVelocityEndY > m_fVelocityStartY ? m_fVelocityStartY : m_fVelocityEndY);
            float tempMaxVY = (m_fVelocityEndY > m_fVelocityStartY ? m_fVelocityEndY : m_fVelocityStartY);
            float rotationV = (float)(r.NextDouble() * Math.PI - Math.PI / 2);
            p.m_fCurrVelocityX = tempMinVX + (float)Math.Cos(rotationV) * (tempMaxVX - tempMinVX);
            p.m_fCurrVelocityY = tempMinVY + (float)Math.Sin(rotationV) * (tempMaxVY - tempMinVY);


            p.m_fCurrScale = m_fScaleStart;
            p.m_fCurrRotation = m_fRotationStart;
            p.m_cCurrColor = cStartColor;

            m_lParticlez.Add(p);         
        }

        private Point m_ptMouse;

        public Point PtMouse
        {
            get { return m_ptMouse; }
            set { m_ptMouse = value; }
        }

        private emitShape eShape;

        public emitShape EShape
        {
            get { return eShape; }
            set { eShape = value; }
        }
        private bool m_bIsLooping;

        public bool BIsLooping
        {
            get { return m_bIsLooping; }
            set { m_bIsLooping = value; }
        }

        private float m_fPositionX;

        public float FPositionX
        {
            get { return m_fPositionX; }
            set { m_fPositionX = value; }
        }

        private float m_fPositionY;

        public float FPositionY
        {
            get { return m_fPositionY; }
            set { m_fPositionY = value; }
        }

        private float m_fVelocityStartX;

        public float FVelocityStartX
        {
            get { return m_fVelocityStartX; }
            set { m_fVelocityStartX = value; }
        }

        private float m_fVelocityEndX;

        public float FVelocityEndX
        {
            get { return m_fVelocityEndX; }
            set { m_fVelocityEndX = value; }
        }

        private float m_fVelocityStartY;

        public float FVelocityStartY
        {
            get { return m_fVelocityStartY; }
            set { m_fVelocityStartY = value; }
        }
        private float m_fVelocityEndY;

        public float FVelocityEndY
        {
            get { return m_fVelocityEndY; }
            set { m_fVelocityEndY = value; }
        }
        private float m_fScaleStart;

        public float FScaleStart
        {
            get { return m_fScaleStart; }
            set { m_fScaleStart = value; }
        }
        private float m_fScaleEnd;

        public float FScaleEnd
        {
            get { return m_fScaleEnd; }
            set { m_fScaleEnd = value; }
        }
        private float m_fSpawnTime;

        public float FSpawnTime
        {
            get { return m_fSpawnTime; }
            set { m_fSpawnTime = value; }
        }
        private float m_fEmissionRate;

        public float FEmissionRate
        {
            get { return m_fEmissionRate; }
            set { m_fEmissionRate = value; }
        }
        private float m_fRotationStart;

        public float FRotationStart
        {
            get { return m_fRotationStart; }
            set { m_fRotationStart = value; }
        }
        private float m_fRotationEnd;

        public float FRotationEnd
        {
            get { return m_fRotationEnd; }
            set { m_fRotationEnd = value; }
        }
        private float m_fMinLife;

        public float FMinLife
        {
            get { return m_fMinLife; }
            set { m_fMinLife = value; }
        }
        private float m_fMaxLife;

        public float FMaxLife
        {
            get { return m_fMaxLife; }
            set { m_fMaxLife = value; }
        }
        private int m_nShape;

        public int NShape
        {
            get { return m_nShape; }
            set { m_nShape = value; }
        }
        private int m_nMaxParticles;

        public int NMaxParticles
        {
            get { return m_nMaxParticles; }
            set { m_nMaxParticles = value; }
        }

        private Color cStartColor;

        public Color CStartColor
        {
            get { return cStartColor; }
            set { cStartColor = value; }
        }
        private Color cEndColor;

        public Color CEndColor
        {
            get { return cEndColor; }
            set { cEndColor = value; }
        }

        private string m_sParticleName;

        public string SParticleName
        {
            get { return m_sParticleName; }
            set { m_sParticleName = value; }
        }

        private int m_nEmitterID;

        public int NEmitterID
        {
            get { return m_nEmitterID; }
            set { m_nEmitterID = value; }
        }
    }
}
